/*
This software is distributed under the Simplified BSD License:

Copyright (c) 2008, Chris Venter <chris.venter@gmail.com>
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, 
    	this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, 
    	this list of conditions and the following disclaimer in the documentation 
    	and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 
DAMAGE.
*/
#ifndef GENERIK_TREEVIEW_UTILS_H
#define GENERIK_TREEVIEW_UTILS_H

/** \file treeviewutils.h
This file defines some utility functions for getting data into and out of a GtkTreeView.
*/

#include <list>
#include <string>

namespace generik
{
	namespace gtk
	{
	
		// utils

		std::string get_pathstring(GtkTreePath* path)
		{
			std::string result;
			gchar* pathstr = gtk_tree_path_to_string(path);
			result = pathstr;
			g_free(pathstr);
			return result;
		}

		// getters

		template <typename TYPE>
		TYPE get_column(GtkTreeModel* model, GtkTreeIter* iter, int column)
		{
			REM_GENERIK_TRACER;
			TYPE value;
			gtk_tree_model_get(model, iter, column, &value, -1);
			GENERIK_TRACE_VALUE(value);
			return value;
		}

		template <>
		std::string get_column<std::string>(GtkTreeModel* model, GtkTreeIter* iter, int column)
		{
			REM_GENERIK_TRACER;
			gchar* value;
			gtk_tree_model_get(model, iter, column, &value, -1);
			GENERIK_TRACE_VALUE(value);
			std::string result = value;
			g_free(value);
			return result;
		}

		template <typename TYPE>
		TYPE get_column(GtkTreeRowReference* row_in, int column_in)
		{
			TYPE value;
			if (!row_in) return value;
			GtkTreeModel* model = gtk_tree_row_reference_get_model(row_in);
			GtkTreePath* path = gtk_tree_row_reference_get_path(row_in);
			GtkTreeIter iter;
			if (gtk_tree_model_get_iter(model, &iter, path))
			{
				return get_column<TYPE>(model, &iter, column_in);
			}
		}

		template <typename TYPE>
		std::list<TYPE> get_selected_columns(GtkTreeView* view, int column)
		{
			std::list<TYPE> results;
			// get the selected menu entry
			GtkTreeModel* model = gtk_tree_view_get_model(view);
			GtkTreeSelection* selection = gtk_tree_view_get_selection(view);
			GList* list = gtk_tree_selection_get_selected_rows(selection, 0);
			if (list)
			{
				while (list)
				{
					GtkTreePath* path = (GtkTreePath*)(list->data);
					if (path)
					{
						GtkTreeIter iter;
						if (gtk_tree_model_get_iter(model, &iter, path))
						{
							TYPE entry = generik::gtk::get_column<TYPE>(model, &iter, column);
							results.push_back(entry);
						}
					}
					list = list->next;
				}
				// dispose of the list
				g_list_foreach(list, (void (*)(void*, void*))gtk_tree_path_free, NULL);
				g_list_free(list);
			}
			//
			return results;
		}
		
		std::list<GtkTreeIter> get_selected_columns(GtkTreeView* view)
		{
			std::list<GtkTreeIter> results;
			// get the selected menu entry(ies)
			GtkTreeModel* model = gtk_tree_view_get_model(view);
			GtkTreeSelection* selection = gtk_tree_view_get_selection(view);
			GList* list = gtk_tree_selection_get_selected_rows(selection, 0);
			if (list)
			{
				while (list)
				{
					GtkTreePath* path = (GtkTreePath*)(list->data);
					if (path)
					{
						GtkTreeIter iter;
						if (gtk_tree_model_get_iter(model, &iter, path))
						{
							results.push_back(iter);
						}
					}
					list = list->next;
				}
				// dispose of the list
				g_list_foreach(list, (void (*)(void*, void*))gtk_tree_path_free, NULL);
				g_list_free(list);
			}
			//
			return results;
		}

		// setters

		template <typename TYPE>
		void set_column(GtkTreeModel* model_in, GtkTreeIter* row_in, TYPE value_in, int column_in)
		{
			REM_GENERIK_TRACER;
			if (!row_in || !model_in) return;

			GENERIK_TRACE_VALUE(value_in);

			GENERIK_GDK_ENTER; // required for asynchronous graphical updates
			gtk_tree_store_set(GTK_TREE_STORE(model_in), row_in, column_in, value_in, -1);
	
			GtkTreePath* path = gtk_tree_model_get_path(model_in, row_in);
			//gchar* pathstr = gtk_tree_path_to_string(path);
			//GENERIK_TRACE_VALUE(pathstr);
			//g_free(pathstr);
			//gtk_tree_model_row_changed(model_in, path, row_in);
			gtk_tree_path_free(path);
		}

		template <typename TYPE>
		void set_column(GtkTreeRowReference* row_in, TYPE value_in, int column_in)
		{
			if (!row_in) return;
			GtkTreeModel* model = gtk_tree_row_reference_get_model(row_in);
			GtkTreePath* path = gtk_tree_row_reference_get_path(row_in);
			GtkTreeIter iter;
			if (gtk_tree_model_get_iter(model, &iter, path))
			{
				set_column<TYPE>(model, &iter, value_in, column_in);
			}
		}

		template <typename TYPE>
		void set_columns(GtkTreeModel* model_in, std::list<GtkTreePath*>& paths_in, TYPE value_in, int column_in)
		{
			for (std::list<GtkTreePath*>::iterator p = paths_in.begin(); p != paths_in.end(); ++p)
			{
				GtkTreeIter iter;
				if (gtk_tree_model_get_iter(model_in, &iter, *p))
				{
					set_column<TYPE>(model_in, &iter, value_in, column_in);
				}
				gtk_tree_path_free(*p);
			}
			paths_in.clear();
		}

		template <typename TYPE>
		struct value_column
		{
			TYPE value;
			int column;
			value_column(TYPE v_in, int c_in) : value(v_in), column(c_in) {}
		};
		template <typename TYPE>
		gboolean set_column_data(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
		{
			value_column<TYPE>* object = (value_column<TYPE>*)data;
			set_column(model, iter, object->value, object->column);
			return false;
		}
		template <typename TYPE>
		void set_all(GtkTreeModel *model_in, TYPE value_in, int column_in)
		{
			value_column<TYPE> object(value_in, column_in);
			gtk_tree_model_foreach(model_in, (GtkTreeModelForeachFunc)&set_column_data<TYPE>, &object);
		}

		// finders

		template <typename TYPE>
		struct value_column_iterok
		{
			TYPE value;
			int column;
			GtkTreeIter iter;
			bool ok;
			value_column_iterok(TYPE v_in, int c_in) : value(v_in), column(c_in), ok(false) {}
		};
		template <typename TYPE>
		gboolean has_value(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
		{
			REM_GENERIK_TRACER;
			value_column_iterok<TYPE>* object = (value_column_iterok<TYPE>*)data;
			if (object->value == get_column<TYPE>(model, iter, object->column))
			{
				GENERIK_TRACE("found a matching iter: ["<<model<<":"<<iter<<"] for ["<<object->value<<"] in column "<<object->column);
				object->iter = *iter;
				object->ok = true;
				return true;
			}
			return false;
		}
		template <typename TYPE>
		bool find_row(GtkTreeModel* model_in, TYPE value, int column, GtkTreeIter& iter_in)
		{
			REM_GENERIK_TRACER;

			GENERIK_TRACE("looking for ["<<value<<"] in column "<<column);
			value_column_iterok<TYPE> object(value, column);
			gtk_tree_model_foreach(model_in, (GtkTreeModelForeachFunc)&has_value<TYPE>, &object);
			if (object.ok)
			{
				GENERIK_TRACE("found iter");
				iter_in = object.iter;
				return true;
			}
			GENERIK_TRACE("failed to found matching iter!");
			return false;
		}

	}

}


#endif



